package com.fire.activiti.activitidb.process.adapter;

import org.activiti.engine.ActivitiException;
import org.activiti.engine.cfg.ProcessEngineConfigurator;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.util.IoUtil;
import org.activiti.engine.impl.util.ReflectUtil;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

/**
 * @author Mr.Fire
 * @date 2021/12/21
 * SqlSessionFactory配置
 */
@Component
public class DbSqlSessionConfigurator implements ProcessEngineConfigurator {

    /**
     * 解决Gbase数据库长字符问题
     */
    private static final String DEFAULT_MYBATIS_MAPPING_FILE = "mapper/mappings.xml";

    private static final List<String> commonDbList=Arrays.asList("dameng","gaussdb100","gbase","oscar","kingbase","polardb");

    private static final List<String> otherDbList=Arrays.asList("hana","derby","gaussdb");

    @Override
    public void beforeInit(ProcessEngineConfigurationImpl processEngineConfiguration) {
        String dbType=processEngineConfiguration.getDatabaseType();
        if (dbType.equals("hana")||dbType.equals("gbase")){
            //添加重写的SqlSessionFactory
            processEngineConfiguration.setBulkInsertEnabled(false);
            processEngineConfiguration.setDbSqlSessionFactory(new ActivitiDbSqlSessionFactory());
        }
    }

    /**
     *  ProcessEngineConfigurationImpl中的configuratorsAfterInit会执行到此处
     */
    @Override
    public void configure(ProcessEngineConfigurationImpl processEngineConfiguration) {
        //创建SqlSessionFactory并设置ProcessEngineConfigurationImpl
        processEngineConfiguration.setSqlSessionFactory(createSqlSessionFactory(processEngineConfiguration));
        //重新执行initDbSqlSessionFactory
        processEngineConfiguration.initDbSqlSessionFactory();

    }

    private SqlSessionFactory createSqlSessionFactory(ProcessEngineConfigurationImpl processEngineConfiguration) {
        InputStream inputStream = null;
        try {
            inputStream = getResourceAsStream(DEFAULT_MYBATIS_MAPPING_FILE);
            Environment environment = new Environment("default", processEngineConfiguration.getTransactionFactory(),
                    processEngineConfiguration.getDataSource());
            Reader reader = new InputStreamReader(inputStream);
            Properties properties = new Properties();
            properties.put("prefix", processEngineConfiguration.getDatabaseTablePrefix());
            String wildcardEscapeClause = "";
            if ((processEngineConfiguration.getDatabaseWildcardEscapeCharacter() != null)
                    && (processEngineConfiguration.getDatabaseWildcardEscapeCharacter().length() != 0)) {
                wildcardEscapeClause = " escape '" + processEngineConfiguration.getDatabaseWildcardEscapeCharacter()
                        + "'";
            }
            properties.put("wildcardEscapeClause", wildcardEscapeClause);
            properties.put("limitBefore", "");
            properties.put("limitAfter", "");
            properties.put("limitBetween", "");
            properties.put("limitOuterJoinBetween", "");
            properties.put("limitBeforeNativeQuery", "");
            properties.put("orderBy", "order by ${orderByColumns}");
            properties.put("blobType", "BLOB");
            properties.put("boolValue", "TRUE");

            if (processEngineConfiguration.getDatabaseType() != null) {
                //设置读取数据库语法配置文件，文件路径src/main/resource/custom/
                if(commonDbList.contains(processEngineConfiguration.getDatabaseType().toLowerCase())) {
                    properties.load(getResourceAsStream("custom/common.properties"));
                }else if(otherDbList.contains(processEngineConfiguration.getDatabaseType().toLowerCase())){
                    properties.load(getResourceAsStream("custom/"+ processEngineConfiguration.getDatabaseType() + ".properties"));
                } else{
                    properties.load(getResourceAsStream("org/activiti/db/properties/"
                            + processEngineConfiguration.getDatabaseType() + ".properties"));
                }

            }

            Configuration configuration = processEngineConfiguration.initMybatisConfiguration(environment, reader,
                    properties);
            return new DefaultSqlSessionFactory(configuration);

        } catch (Exception e) {
            throw new ActivitiException("Error while building ibatis SqlSessionFactory: " + e.getMessage(), e);
        } finally {
            IoUtil.closeSilently(inputStream);
        }

    }

    private InputStream getResourceAsStream(String resource) {
        return ReflectUtil.getResourceAsStream(resource);
    }

    @Override
    public int getPriority() {
        return 0;
    }
}